/*
PearReview - The peer review assistant.
Copyright (C) 2009  Dimitrij Pankratz, Anton Musichin
http://www.pearreview.com, info@pearreview.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package com.pearreview.ui;

import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.JTextComponent;

import com.pearreview.application.Messages;

public class CutCopyPasteManager implements Serializable {
	private static final long serialVersionUID = -2214264689504656126L;
	
	private static CutCopyPasteManager instance;
	
	private CutCopyPasteManager() {
	}
	
	public static CutCopyPasteManager getInstance() {
		if(instance == null)
			instance = new CutCopyPasteManager();
		return instance;
	}
	
	private static String getLocalizedStrin(String key) {
		return Messages.getString("PearReview.edit." + key);
	}
	
	private Icon getResourceIcon(String name) {
		return new ImageIcon(getClass().getResource("images/" + name));
	}
	
	public void registerJTextComponent(JTextComponent comp) {
		JPopupMenu popup = new JPopupMenu();
		
		KeyStroke ks;
		int mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
		
		JMenuItem cutItem = new JMenuItem(getLocalizedStrin("cut"));
		ks = KeyStroke.getKeyStroke(KeyEvent.VK_X, mask);
		cutItem.setAccelerator(ks);
		cutItem.setIcon(getResourceIcon("edit-cut.png"));
		cutItem.addActionListener(new CutListener(comp));
		
		JMenuItem copyItem = new JMenuItem(getLocalizedStrin("copy"));
		ks = KeyStroke.getKeyStroke(KeyEvent.VK_C, mask);
		copyItem.setAccelerator(ks);
		copyItem.setIcon(getResourceIcon("edit-copy.png"));
		copyItem.addActionListener(new CopyListener(comp));
		
		JMenuItem pasteItem = new JMenuItem(getLocalizedStrin("paste"));
		ks = KeyStroke.getKeyStroke(KeyEvent.VK_V, mask);
		pasteItem.setAccelerator(ks);
		pasteItem.setIcon(getResourceIcon("edit-paste.png"));
		pasteItem.addActionListener(new PasteListener(comp));
		
		JMenuItem selectItem = new JMenuItem(getLocalizedStrin("select"));
		ks = KeyStroke.getKeyStroke(KeyEvent.VK_A, mask);
		selectItem.setAccelerator(ks);
		selectItem.setIcon(getResourceIcon("edit-select.png"));
		selectItem.addActionListener(new SelectListener(comp));
		
		popup.add(cutItem);
		popup.add(copyItem);
		popup.add(pasteItem);
		popup.add(selectItem);
		
		comp.addMouseListener(new ContextMouseListener(comp, popup));
		
		comp.addKeyListener(new ContextKeyListener(comp, popup));
		
		comp.addCaretListener(new ComponentCaretListener(cutItem, copyItem));
		
		comp.addPropertyChangeListener( 
				new ComponentPropertyListener(comp, cutItem, pasteItem));
	}
	
	private class CutListener implements ActionListener, Serializable {
		private static final long serialVersionUID = -2462394083643005368L;
		private JTextComponent comp;
		public CutListener(JTextComponent comp) {
			this.comp = comp;
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			comp.cut();
		}
	}
	
	private class PasteListener implements ActionListener, Serializable {
		private static final long serialVersionUID = 2902557816956567589L;
		private JTextComponent comp;
		public PasteListener(JTextComponent comp) {
			this.comp = comp;
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			comp.paste();
		}
	}
	
	private class CopyListener implements ActionListener, Serializable {
		private static final long serialVersionUID = -1545670119354134967L;
		private JTextComponent comp;
		public CopyListener(JTextComponent comp) {
			this.comp = comp;
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			comp.copy();
		}
	}
	
	private class SelectListener implements ActionListener, Serializable {
		private static final long serialVersionUID = -2462394083643005368L;
		private JTextComponent comp;
		public SelectListener(JTextComponent comp) {
			this.comp = comp;
		}
		@Override
		public void actionPerformed(ActionEvent e) {
			comp.selectAll();
		}
	}
	
	private class ContextMouseListener extends MouseAdapter 
			implements Serializable {
		private static final long serialVersionUID = 7728807937165919484L;
		private JPopupMenu popup;
		private JTextComponent comp;
		ContextMouseListener(JTextComponent comp, JPopupMenu popup) {
			this.popup = popup;
			this.comp = comp;
		}
		@Override
		public void mousePressed(MouseEvent e) {
			popup(e);
		}
		@Override
		public void mouseReleased(MouseEvent e) {
			popup(e);
		}
		private void popup(MouseEvent e) {
			if (e.isPopupTrigger() && comp.isVisible() && comp.isEnabled()) {
				comp.requestFocusInWindow();
				popup.show(e.getComponent(), e.getX(), e.getY());
			}
		}
	}
	
	private class ContextKeyListener implements KeyListener, Serializable {
		private static final long serialVersionUID = 1700236691132467166L;
		private JTextComponent comp;
		private JPopupMenu popup;
		public ContextKeyListener(JTextComponent comp, JPopupMenu popup) {
			this.comp = comp;
			this.popup = popup;
		}
		@Override
		public void keyPressed(KeyEvent e) { }
		@Override
		public void keyReleased(KeyEvent e) {
			if (e.getKeyCode() == KeyEvent.VK_CONTEXT_MENU) {
				Point pos = comp.getCaret().getMagicCaretPosition();
				if (pos == null) {
					popup.show(comp, 0, 0);
				} else {
					popup.show(comp, pos.x, pos.y);
				}
			}
		}
		@Override
		public void keyTyped(KeyEvent e) { }
	}
	
	private class ComponentCaretListener implements CaretListener, Serializable{
		private static final long serialVersionUID = 7311847679651235367L;
		private JMenuItem cutItem;
		private JMenuItem copyItem; 
		public ComponentCaretListener(JMenuItem cutItem, JMenuItem copyItem) {
			this.cutItem = cutItem;
			this.copyItem = copyItem;
		}
		@Override
		public void caretUpdate(CaretEvent e) {
			if (e.getDot() != e.getMark()) {
				copyItem.setEnabled(true);
				cutItem.setEnabled(true);
			} else {
				copyItem.setEnabled(false);
				cutItem.setEnabled(false);
			}
		}
	}
	
	private class ComponentPropertyListener implements PropertyChangeListener,
			Serializable {
		private static final long serialVersionUID = 2011690399137818316L;
		private JTextComponent comp;
		private JMenuItem cutItem;
		private JMenuItem pasteItem;
		public ComponentPropertyListener(JTextComponent comp, JMenuItem cutItem,
				JMenuItem pasteItem) {
			this.comp = comp;
			this.cutItem = cutItem;
			this.pasteItem = pasteItem;
			validate();
		}
		private void validate() {
			cutItem.setVisible(comp.isEditable());
			pasteItem.setVisible(comp.isEditable());
		}
		@Override
		public void propertyChange(PropertyChangeEvent e) {
			if("editable".equals(e.getPropertyName()))
				validate();
		}
	}
}
